#include "ibma_in.h"

static sig_atomic_t	g_SIGTERM_flag = 0 ;
sig_atomic_t		g_CLEAN_SPACE_ON_QUIT_flag = 0 ;
static sig_atomic_t	g_SIGUSR1_flag = 0 ;

static void sig_set_flag( int sig_no )
{
	if( sig_no == SIGTERM )
	{
		g_SIGTERM_flag = 1 ;
	}
	else if( sig_no == SIGUSR1 )
	{
		g_SIGUSR1_flag = 1 ;
	}
	else if( sig_no == SIGUSR2 )
	{
		g_SIGTERM_flag = 1 ;
		g_CLEAN_SPACE_ON_QUIT_flag = 1 ;
	}
	
	return;
}

static int worker( struct IbmaEnv *p_env )
{
	struct sigaction	act ;
	
	struct ConfigSpace	*p_config_space = NULL ;
	struct ConfigSpace	*p_next_config_space = NULL ;
	struct shmid_ds		shmds ;
	
	struct HttpBuffer	*b = NULL ;
	
	int			nret = 0 ;
	
	act.sa_handler = & sig_set_flag ;
	sigemptyset( & (act.sa_mask) );
	act.sa_flags = 0 ;
	sigaction( SIGTERM , & act , NULL );
	sigaction( SIGUSR2 , & act , NULL );
	act.sa_flags = SA_RESTART ;
	sigaction( SIGUSR1 , & act , NULL );
	
	while( ! g_SIGTERM_flag )
	{
		if( g_SIGUSR1_flag == 1 )
		{
			char		*file_content = NULL ;
			int		file_len ;
			ibma_conf	ibma_conf ;
			
			g_SIGUSR1_flag = 0 ;
			
			file_content = StrdupEntireFile( p_env->ibma_conf_pathfilename , & file_len ) ;
			if( file_content == NULL )
			{
				ERRORLOGSG( "StrdupEntireFile[%s] failed" , p_env->ibma_conf_pathfilename );
				continue;
			}
			
			memset( & ibma_conf , 0x00 , sizeof(ibma_conf) );
			nret = DSCDESERIALIZE_JSON_ibma_conf( "GB18030" , file_content , & file_len , & ibma_conf ) ;
			free( file_content );
			if( nret )
			{
				ERRORLOGSG( "DSCDESERIALIZE_JSON_ibma_conf[%s] failed[%d]" , p_env->ibma_conf_pathfilename , nret );
				continue;
			}
			
			strcpy( p_env->ibma_conf.ibma.log.iblog_server , ibma_conf.ibma.log.iblog_server );
			strcpy( p_env->ibma_conf.ibma.log.event_output , ibma_conf.ibma.log.event_output );
			strcpy( p_env->ibma_conf.ibma.log.worker_loglevel , ibma_conf.ibma.log.worker_loglevel );
			strcpy( p_env->ibma_conf.ibma.log.worker_output , ibma_conf.ibma.log.worker_output );
			
			INFOLOGSG( "InitLogEnv iblog_server[%s] event_output[%s] worker_output[%s][%s]" , p_env->ibma_conf.ibma.log.iblog_server , p_env->ibma_conf.ibma.log.event_output , p_env->ibma_conf.ibma.log.worker_loglevel , p_env->ibma_conf.ibma.log.worker_output );
			IBPCleanLogEnv();
			IBPInitLogEnv( p_env->ibma_conf.ibma.log.iblog_server , "ibma.worker" , p_env->ibma_conf.ibma.log.event_output , IBPConvertLogLevel(ibma_conf.ibma.log.worker_loglevel) , "%s" , p_env->ibma_conf.ibma.log.worker_output );
			INFOLOGSG( "InitLogEnv iblog_server[%s] event_output[%s] worker_output[%s][%s]" , p_env->ibma_conf.ibma.log.iblog_server , p_env->ibma_conf.ibma.log.event_output , p_env->ibma_conf.ibma.log.worker_loglevel , p_env->ibma_conf.ibma.log.worker_output );
		}
		
		list_for_each_entry_safe( p_config_space , p_next_config_space , & (p_env->config_space_list.this_node) , struct ConfigSpace , this_node )
		{
			if( p_config_space == p_env->p_current_config_space )
				continue;
			
			memset( & shmds , 0x00 , sizeof(struct shmid_ds) );
			nret = shmctl( p_config_space->shm.shmid , IPC_STAT , & shmds ) ;
			INFOLOGSG( "stat config_space[0x%X][%d] nattch[%d]" , p_config_space->shm.shmkey , p_config_space->shm.shmid , shmds.shm_nattch );
			if( nret == -1 || shmds.shm_nattch == 1 )
			{
				if( p_config_space->shm.base )
				{
					shmdt( p_config_space->shm.base );
					p_config_space->shm.base = NULL ;
				}
				shmctl( p_config_space->shm.shmid , IPC_RMID , NULL );
				INFOLOGSG( "del config_space[0x%X][%d]" , p_config_space->shm.shmkey , p_config_space->shm.shmid );
				list_del( & (p_config_space->this_node) );
				free( p_config_space );
			}
		}
		
		if( p_env->netaddr.sock == -1 )
		{
			nret = ConnectToIbmsServer( p_env ) ;
			if( nret )
			{
				FATALLOGSG( "ConnectIbmsServer failed[%d]" , nret );
				sleep( 10 );
				continue;
			}
			else
			{
				INFOLOGSG( "ConnectIbmsServer ok" );
			}
			
			nret = OnProcessBuildConfigSpace( p_env , GetHttpResponseBuffer(p_env->http) ) ;
			if( nret != HTTP_OK )
			{
				FATALLOGSG( "OnProcessBuildConfigSpace failed[%d]" , nret );
				return -1;
			}
			else
			{
				INFOLOGSG( "OnProcessBuildConfigSpace ok" );
			}
			
			SetHttpNonblock( p_env->netaddr.sock );
			SetHttpTimeout( p_env->http , -1 );
			ResetHttpEnv( p_env->http );
			ResetHttpSecureEnv( p_env->http_secure_env );
		}
		
		nret = ReceiveHttpRequestNonblock( p_env->netaddr.sock , NULL , p_env->http ) ;
		if( nret == FASTERHTTP_INFO_NEED_MORE_HTTP_BUFFER )
		{
			INFOLOGSG( "ReceiveHttpRequestNonblock [%d]bytes read" , GetHttpBufferLength(GetHttpRequestBuffer(p_env->http)) );
		}
		else if( nret )
		{
			ERRORLOGSG( "ReceiveHttpRequestNonblock failed[%d]" , nret );
			DisconnectFromIbmsServer( p_env );
			sleep(1);
			continue;
		}
		else
		{
			INFOLOGSG( "ReceiveHttpRequestNonblock done" );
			
			b = GetHttpRequestBuffer( p_env->http ) ;
			DEBUGHEXLOGSG( GetHttpBufferBase(b,NULL) , GetHttpBufferLength(b) , "RequestBuffer" );
			
			nret = FormatHttpResponseStartLine( HTTP_OK , p_env->http , 1 , NULL ) ;
			if( nret )
			{
				ERRORLOGSG( "FormatHttpResponseStartLine failed[%d]" , nret );
				return -1;
			}
			
			b = GetHttpResponseBuffer( p_env->http ) ;
			DEBUGHEXLOGSG( GetHttpBufferBase(b,NULL) , GetHttpBufferLength(b) , "ResponseBuffer" );
			
			SetHttpBlock( p_env->netaddr.sock );
			nret = SendHttpResponse( p_env->netaddr.sock , NULL , p_env->http ) ;
			SetHttpNonblock( p_env->netaddr.sock );
			if( nret )
			{
				ERRORLOGSG( "SendHttpResponse failed[%d]" , nret );
				DisconnectFromIbmsServer( p_env );
				sleep(1);
				continue;
			}
			else
			{
				INFOLOGSG( "SendHttpResponse done" );
			}
			
			{
			char		*METHOD = NULL ;
			int		METHOD_LEN ;
			char		*URI = NULL ;
			int		URI_LEN ;
			char		*VERSION = NULL ;
			int		VERSION_LEN ;
			char		*STATUS_CODE = NULL ;
			int		STATUS_CODE_LEN ;
			
			METHOD = GetHttpHeaderPtr_METHOD( p_env->http , & METHOD_LEN );
			URI = GetHttpHeaderPtr_URI( p_env->http , & URI_LEN );
			VERSION = GetHttpHeaderPtr_VERSION( p_env->http , & VERSION_LEN );
			STATUS_CODE = GetHttpHeaderPtr_STATUSCODE( p_env->http , & STATUS_CODE_LEN );
			
			NOTICELOGSG( "[%s][%s:%d] -> [%s][%s:%d] [%.*s %.*s %.*s] [%.*s]"
					, "ibms" , p_env->ibma_conf.ibms.server.ip , p_env->ibma_conf.ibms.server.port
					, p_env->ibma_conf.ibma.node , p_env->netaddr.local_ip , p_env->netaddr.local_port
					, METHOD_LEN , METHOD
					, URI_LEN , URI
					, VERSION_LEN , VERSION
					, STATUS_CODE_LEN , STATUS_CODE );
			}
			
			nret = OnProcess( p_env ) ;
			if( nret != HTTP_OK )
			{
				ERRORLOGSG( "OnProcess failed[%d]" , nret );
			}
			else
			{
				INFOLOGSG( "OnProcess ok" );
			}
			
			ResetHttpEnv( p_env->http );
			ResetHttpSecureEnv( p_env->http_secure_env );
		}
		
		sleep(1);
	}
	
	return 0;
}

int _worker( void *pv )
{
	struct IbmaEnv	*p_env = (struct IbmaEnv*)pv ;
	
	int		nret = 0 ;
	
	IBPCleanLogEnv();
	IBPInitLogEnv( p_env->ibma_conf.ibma.log.iblog_server , "ibma.worker" , p_env->ibma_conf.ibma.log.event_output , IBPConvertLogLevel(p_env->ibma_conf.ibma.log.worker_loglevel) , "%s" , p_env->ibma_conf.ibma.log.worker_output );
	
	INFOLOGSG( "--- ibma.worker begin --- " );
	
	nret = worker( p_env ) ;
	
	INFOLOGSG( "--- ibma.worker end --- " );
	
	CleanEnvironment( p_env );
	free( p_env );
	exit(0);
}

